#include <queue>
#include <iostream>
#include <pthread.h>
const int MAXCAPACITY = 5;
namespace BlockModule
{
    template <typename T>
    class BlockQueue
    {

    private:
        bool IsEmpty()
        {
            return _q.size() == 0;
        }
        bool IsFull()
        {
            return _q.size() == MAXCAPACITY;
        }

    public:
        BlockQueue() : _cap(MAXCAPACITY), _csleep_num(0), _psleep_num(0)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_emptycond, nullptr);
            pthread_cond_init(&_fullcond, nullptr);
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_fullcond);
            pthread_cond_destroy(&_emptycond);
        }

        void Equeue(const T &in)
        {
            // 多个生产者
            pthread_mutex_lock(&_mutex);
            // 生产者进行入队
            //这里用while是因为当我们一次唤醒多个线程
            //前一个线程可能已经把队列干满了
            //但是最后一个进程醒来将会继续入队导致队列满
            while (IsFull())
            {
                // 生产者要去等待
                // 等待把锁释放可以给消费者
                _psleep_num++;
                std::cout << "生产者，进入休眠了: _psleep_num" << _psleep_num << std::endl;
                pthread_cond_wait(&_fullcond, &_mutex);
                _psleep_num--;
            }
            // 此时插入数据
            _q.push(in);
            // 此时队列一定有数据唤醒消费者去消费
            if (_csleep_num > 0)
            {
                std::cout << "唤醒消费者..." << std::endl;
                pthread_cond_signal(&_emptycond);
            }
            //解锁
            pthread_mutex_unlock(&_mutex);
        }
        T Pop()
        {
            //消费者会进行操作
            //我们要维护消费者之间的互斥
            pthread_mutex_lock(&_mutex);
            //队列有数据才可以进行没有去等待
            while(IsEmpty())
            {
                //此时线程去等待
                _csleep_num++;
                std::cout<<"消费者,进入休眠了:"<<_csleep_num<<std::endl;
                //消费者休眠把锁释放
                pthread_cond_wait(&_emptycond,&_mutex);
                _csleep_num--;
            }
            //此时一定有数据
            T data=_q.front();
            _q.pop();
            std::cout<<"消费者拿走了一个任务"<<std::endl;
            //拿走一个数据此时队列一定不为满
            if(_psleep_num>0)
            {
                std::cout<<"唤醒生产者"<<std::endl;
                pthread_cond_signal(&_fullcond);

            }
            pthread_mutex_unlock(&_mutex);
            return data;
        }

    private:
        std::queue<T> _q;
        int _cap;

        pthread_mutex_t _mutex;
        pthread_cond_t _fullcond;  // 队列满生产者去改条件变量等待
        pthread_cond_t _emptycond; // 消费者等待

        int _psleep_num; // 消费者休眠的个数
        int _csleep_num; // 生产者休眠的个数
    };
}